package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/pflag"
)

func loadConfig(path string) (Config, error) {
	f, err := os.Open(path)
	if err != nil {
		return Config{}, err
	}
	defer f.Close() // nolint
	content, err := ioutil.ReadAll(f)
	if err != nil {
		return Config{}, err
	}
	var config Config
	err = json.Unmarshal(content, &config)
	return config, err
}

type Sender interface {
	Send(data []byte) error
}

func isValidMac(mac interface{}) bool {
	switch v := mac.(type) {
	case string:
		{
			if len(v) == 0 {
				return false
			}
			return true
		}
	default:
		return false
	}
}

func encodeMac(mac string) (string, error) {
	mac = strings.Replace(mac, ":", "", -1)
	mac = strings.ToUpper(mac)
	return mac, nil
}

type T6006GPS struct {
	Latitude  string `json:"latitude"`
	Longitude string `json:"longitude"`
	Province  string `json:"province"`
	TrueTrack string `json:"true_track"`
	SpeedKmh  string `json:"speed_kmh"`
}

type T6006 struct {
	ISP     string   `json:"isp"`
	Signal  int      `json:"signal"`
	Service string   `json:"service"`
	Yaw     string   `json:"yaw"`
	Time    string   `json:"time"`
	Depth   string   `json:"depth"`
	Mac     string   `json:"mac"`
	Pitch   string   `json:"pitch"`
	Roll    string   `json:"roll"`
	GPS     T6006GPS `json:"gps"`
}

func formatJSON(data T6006) map[string]interface{} {
	m := map[string]interface{}{}
	m["isp"] = data.ISP
	m["signal"] = data.Signal
	m["service"] = data.Service
	m["yaw"], _ = strconv.ParseFloat(data.Yaw, 64)
	m["time"] = data.Time
	m["depth"], _ = strconv.ParseFloat(data.Depth, 64)
	m["mac"] = data.Mac
	m["pitch"], _ = strconv.ParseFloat(data.Pitch, 64)
	m["roll"], _ = strconv.ParseFloat(data.Roll, 64)
	m["longitude"], _ = strconv.ParseFloat(data.GPS.Longitude, 64)
	m["latitude"], _ = strconv.ParseFloat(data.GPS.Latitude, 64)
	m["province"] = data.GPS.Province
	m["true_track"], _ = strconv.ParseFloat(data.GPS.TrueTrack, 64)
	m["speed_kmh"], _ = strconv.ParseFloat(data.GPS.SpeedKmh, 64)
	return m
}

func makeHandler(sender Sender) func(conn net.Conn) {
	return func(conn net.Conn) {
		for {
			data, err := bufio.NewReader(conn).ReadString('\n')
			if err != nil {
				log.WithFields(log.Fields{"err": err}).Error("")
				conn.Close()
				return
			}
			log.WithFields(log.Fields{"data": data}).Info("received data")
			bytes := []byte(data)
			var m T6006
			err = json.Unmarshal(bytes, &m)
			if err != nil {
				log.WithFields(log.Fields{"err": err}).Error("error parsing received data")
				continue
			}
			mac := m.Mac
			tmac, err := encodeMac(mac)
			if err != nil {
				log.WithFields(log.Fields{"err": err, "mac": mac}).Error("error format mac")
			}
			msg := map[string]interface{}{}
			msg["id"] = tmac

			msg["data"] = formatJSON(m)
			res, err := json.Marshal(msg)
			if err != nil {
				continue
			}
			err = sender.Send(res)
			if err != nil {
				log.WithFields(log.Fields{"err": err}).Error("send error")
			} else {
				log.WithFields(log.Fields{"msg": msg}).Info("send msg")
			}
		}
	}
}

func main() {
	cfgFile := pflag.StringP("config", "c", "", "")
	pflag.Parse()
	if *cfgFile == "" {
		fmt.Printf("must provide config file")
		os.Exit(-1)
	}
	config, err := loadConfig(*cfgFile)
	if err != nil {
		panic(err)
	}

	// ch := make(chan rdata)
	sender, err := NewUDPSender(config.UDPSenderConfig)
	if err != nil {
		panic(err)
	}
	handler := makeHandler(sender)

	receiver, err := NewTCPReceiver(config.TCPSenderConfig, handler)
	if err != nil {
		panic(err)
	}
	err = receiver.Open()
	if err != nil {
		panic(err)
	}
	err = receiver.Start()
	if err != nil {
		panic(err)
	}

	ch := make(chan int)
	<-ch
}
